package ar.com.solidussource.howmuchmobile.maps.tools;

import android.content.Context;
import android.util.AttributeSet;
import android.view.GestureDetector;
import android.view.GestureDetector.OnDoubleTapListener;
import android.view.GestureDetector.OnGestureListener;
import android.view.MotionEvent;
import com.google.android.maps.GeoPoint;
import com.google.android.maps.MapView;

import java.util.Timer;
import java.util.TimerTask;

public class MapViewWithChangeListener extends MapView implements
        OnGestureListener {

    private GestureDetector gd;

    // ------------------------------------------------------------------------
    // LISTENER DEFINITIONS
    // ------------------------------------------------------------------------

    // Change listener
    public interface OnChangeListener {
        public void onChange(MapView view, GeoPoint newCenter,
                             GeoPoint oldCenter, int newZoom, int oldZoom);
    }

    // ------------------------------------------------------------------------
    // MEMBERS
    // ------------------------------------------------------------------------

    private MapViewWithChangeListener mThis;
    private long mEventsTimeout = 250L; // Set this variable to your preferred
    // timeout
    private boolean mIsTouched = false;
    private GeoPoint mLastCenterPosition;
    private int mLastZoomLevel;
    private Timer mChangeDelayTimer = new Timer();
    private MapViewWithChangeListener.OnChangeListener mChangeListener = null;

    // ------------------------------------------------------------------------
    // CONSTRUCTORS
    // ------------------------------------------------------------------------

    public MapViewWithChangeListener(Context context, String apiKey) {
        super(context, apiKey);
        setupGestures();
        init();
    }

    public MapViewWithChangeListener(Context context, AttributeSet attrs) {
        super(context, attrs);
        setupGestures();
        init();
    }

    public MapViewWithChangeListener(Context context, AttributeSet attrs,
                                     int defStyle) {
        super(context, attrs, defStyle);
        setupGestures();
        init();
    }

    private void setupGestures() {
        gd = new GestureDetector(this);

        // set the on Double tap listener
        gd.setOnDoubleTapListener(new OnDoubleTapListener() {

            public boolean onDoubleTap(MotionEvent e) {
                MapViewWithChangeListener.this.getController().zoomInFixing(
                        (int) e.getX(), (int) e.getY());
                return false;
            }

            public boolean onDoubleTapEvent(MotionEvent e) {
                return false;
            }

            public boolean onSingleTapConfirmed(MotionEvent arg0) {
                return false;
            }

        });
    }

    private void init() {
        mThis = this;
        mLastCenterPosition = this.getMapCenter();
        mLastZoomLevel = this.getZoomLevel();
    }

    // ------------------------------------------------------------------------
    // GETTERS / SETTERS
    // ------------------------------------------------------------------------

    public void setOnChangeListener(MapViewWithChangeListener.OnChangeListener l) {
        mChangeListener = l;
    }

    // ------------------------------------------------------------------------
    // EVENT HANDLERS
    // ------------------------------------------------------------------------

    @Override
    public boolean onTouchEvent(MotionEvent ev) {

        if (this.gd.onTouchEvent(ev)) {
            // Set touch internal
            mIsTouched = (ev.getAction() != MotionEvent.ACTION_UP);
            return true;
        } else {
            return super.onTouchEvent(ev);
        }

        // // Set touch internal
        // mIsTouched = (ev.getAction() != MotionEvent.ACTION_UP);
        //
        // return super.onTouchEvent(ev);
    }

    @Override
    public void computeScroll() {
        super.computeScroll();

        // Check for change
        if (isSpanChange() || isZoomChange()) {
            // If computeScroll called before timer counts down we should drop
            // it and
            // start counter over again
            resetMapChangeTimer();
        }
    }

    // ------------------------------------------------------------------------
    // TIMER RESETS
    // ------------------------------------------------------------------------

    private void resetMapChangeTimer() {
        mChangeDelayTimer.cancel();
        mChangeDelayTimer = new Timer();
        mChangeDelayTimer.schedule(new TimerTask() {
            @Override
            public void run() {
                if (mChangeListener != null)
                    mChangeListener
                            .onChange(mThis, getMapCenter(),
                                    mLastCenterPosition, getZoomLevel(),
                                    mLastZoomLevel);
                mLastCenterPosition = getMapCenter();
                mLastZoomLevel = getZoomLevel();
            }
        }, mEventsTimeout);
    }

    // ------------------------------------------------------------------------
    // CHANGE FUNCTIONS
    // ------------------------------------------------------------------------

    private boolean isSpanChange() {
        return !mIsTouched && !getMapCenter().equals(mLastCenterPosition);
    }

    private boolean isZoomChange() {
        return (getZoomLevel() != mLastZoomLevel);
    }

    public boolean onDown(MotionEvent e) {
        // TODO Auto-generated method stub
        return false;
    }

    public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX,
                           float velocityY) {
        // TODO Auto-generated method stub
        return false;
    }

    public void onLongPress(MotionEvent e) {
        // TODO Auto-generated method stub

    }

    public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX,
                            float distanceY) {
        // TODO Auto-generated method stub
        return false;
    }

    public void onShowPress(MotionEvent e) {
        // TODO Auto-generated method stub

    }

    public boolean onSingleTapUp(MotionEvent e) {
        this.removeAllViews();
        return false;
    }

}